package chat

import (
	"api/internal/svc"
	"encoding/json"
	"github.com/gorilla/websocket"
	"github.com/zeromicro/go-zero/core/logx"
	"net/http"
	"strconv"
	"strings"
	"user_srv/user"
)

// WebSocketHandler 处理WebSocket连接请求与消息收发，依赖服务上下文访问RPC等资源
func WebSocketHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 检查请求头的Upgrade字段，判断是否为WebSocket握手请求（标准WebSocket请求会包含Upgrade: websocket）
		isWebSocket := strings.ToLower(r.Header.Get("Upgrade")) == "websocket"
		if isWebSocket {
			logx.Info("收到WebSocket连接请求") // 调试日志：标记WebSocket类型的连接请求
		}

		// 创建WebSocket升级器：用于将HTTP连接升级为WebSocket连接
		upgrader := websocket.Upgrader{
			// 跨域检查函数：开发阶段临时允许所有跨域，生产环境需替换为基于域名的严格校验
			CheckOrigin: func(r *http.Request) bool {
				return true // 允许所有跨域请求，生产环境应该更严格
			},
		}

		// 解析请求的Form数据（中间件需提前将用户ID注入Form中）
		r.ParseForm()
		userIdStr := r.Form.Get("userId")
		logx.Info("从Form中获取的用户ID:", userIdStr) // 调试日志：输出获取到的用户ID字符串

		// 校验用户ID是否存在，不存在则返回401未授权
		if userIdStr == "" {
			logx.Error("用户ID不存在于Form中，请检查中间件配置")
			http.Error(w, "认证失败：用户信息缺失", http.StatusUnauthorized)
			return
		}

		// 将字符串类型的用户ID转换为整数，方便后续逻辑使用
		userId, err := strconv.Atoi(userIdStr)
		if err != nil {
			logx.Error("用户ID格式错误：", err) // 记录用户ID转换失败的错误
			http.Error(w, "认证失败：用户信息格式错误", http.StatusInternalServerError)
			return
		}
		logx.Info("成功解析用户ID:", userId) // 调试日志：输出转换后的整数用户ID

		// 升级 HTTP 连接为 WebSocket 连接
		logx.Info("尝试升级WebSocket连接")
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			logx.Error("WebSocket 升级失败:", err) // 记录连接升级失败的错误
			// 细分错误类型，辅助定位问题（如握手阶段的请求头错误）
			if _, ok := err.(websocket.HandshakeError); ok {
				logx.Error("WebSocket握手错误: 可能是请求头不正确")
			}
			return
		}
		logx.Info("WebSocket连接升级成功")
		defer conn.Close() // 函数结束时自动关闭连接，防止资源泄漏

		// 透传HTTP请求的上下文（用于超时控制、链路追踪等场景）
		ctx := r.Context()

		// 持续监听WebSocket消息（长连接核心逻辑）
		for {
			// 从WebSocket连接中读取消息（忽略消息类型，获取 payload 字节流 p）
			_, p, err := conn.ReadMessage()
			if err != nil {
				logx.Error("读取消息失败:", err) // 记录消息读取失败的错误（如客户端断开）
				break                      // 读取失败时退出循环，结束当前连接的消息监听
			}

			// 定义接收客户端消息的结构体（对应JSON格式）
			var Message WsProduce // 声明消息结构体变量
			// 将JSON字节流解析到结构体中
			err = json.Unmarshal(p, &Message)
			if err != nil {
				// 向客户端反馈消息格式错误，继续下一次消息读取
				logx.Error("JSON 解析失败:", err)
				conn.WriteMessage(websocket.TextMessage, []byte("消息格式错误"))
				continue
			}
			// 调用RPC服务发送消息（通过服务上下文的RPC客户端发起远程调用）
			message, err := svcCtx.UserRpc.SendMessage(ctx, &user.SendMessageReq{
				SenderId:   int64(userId),           // 发送者ID（从请求中获取）
				ReceiverId: int64(Message.ToUserId), // 接收者ID（从消息结构体中获取）
				Content:    Message.Message,         // 消息内容（从消息结构体中获取）
				Type:       int32(Message.Type),     // 消息类型（从消息结构体中获取）
			})

			if err != nil {
				logx.Error("RPC 调用失败:", err)
				conn.WriteMessage(websocket.TextMessage, []byte("服务失败"))
				continue
			}

			if !message.Success {
				conn.WriteMessage(websocket.TextMessage, []byte("消息推送失败"))
				continue
			}

			conn.WriteMessage(websocket.TextMessage, []byte("消息发送成功"))
		}
	}
}

// WsProduce 定义 WebSocket 消息结构
type WsProduce struct {
	ToUserId int    `json:"to_user_id"`
	Message  string `json:"message"`
	Type     int    `json:"type"`
}
